#include "Threading.hpp"

int Threading::max_thread_id = 0;
std::unordered_map<std::thread::id, int> Threading::threadIdMap;
std::unordered_map<int, std::thread::id> Threading::idThreadMap;

#ifndef DEBUG_NUMA
void Threading::dumpThreadInfo(std::ostream &, std::string const &) {
#else
void Threading::dumpThreadInfo(std::ostream & os, std::string const &s) {
  std::stringstream ss;
  uint cpu, node = 0;
  // sys_getcpu(&cpu, &node);
  cpu = sched_getcpu();
  node = numa_node_of_cpu(cpu);
  ss << "I am " << std::this_thread::get_id() << " processing " << s << 
    " and running on cpu=" << cpu << " node=" << node << "\n";
  Threading::dump(os, ss.str());
#endif // DEBUG_NUMA
}

#ifndef DEBUG_NUMA_MEM
void Threading::dumpMemInfo(std::ostream &, void *) {
#else
void Threading::dumpMemInfo(std::ostream & os, void *addr) {
  static __thread int count = 0;
  static __thread int same = 0.0;
  static __thread int different = 0.0;

  uint cpu = 0, node = 0;
  cpu = sched_getcpu();
  node = numa_node_of_cpu(cpu);

  count++;

  int status;
  move_pages(0 /*self memory */, 1, &addr, NULL, &status, 0);    
  int inc = ((status == node) ? 1 : 0);

  same += inc;
  different += (1-inc);

  if (count % DEBUG_NUMA_MEM == 0) {
    std::stringstream ss;
    ss << "I am thread " << Threading::threadIdMap[std::this_thread::get_id()]
       << " (count: " << std::dec << count << ")"
       << " running on cpu:" << std::dec << cpu << " on node:" 
       << node;// << std::hex;
    ss << "\t Page @0x" << ((int64_t)addr & 0xfffffffffffff700)
       << std::dec << "  on node: " << status;
    ss << " same node access " << ((100.0*same)/(same+different)) << "% ("
       << same << "/" << (same+different) << ")"
       << std::dec << " (count: " << count << ")\n";
    Threading::dump(os, ss.str());
    ss << std::dec;
  }
#endif // DEBUG_NUMA_MEM
}
